Python 使用 ElementTree 寫入 XML 格式檔案與縮排


Posted by 小江 on 2022-11-17

目標產出

Output.xml

<EDC>
  <object_id>OBJ_ID</object_id>
  <product_id>PROD_ID</product_id>
  <eqp_id>EQP_ID</eqp_id>
  <owner></owner>
  <recipe_id>RECIPE_ID</recipe_id>
  <operation>OPER</operation>
  <cldate>2022-11-16</cldate>
  <cltime>23:25:39</cltime>
  <datas>
    <iary>
      <item_name>illuminance_B_NA</item_name>
      <item_type>X</item_type>
      <item_value>751</item_value>
    </iary>
    <iary>
      <item_name>illuminance_B_PL</item_name>
      <item_type>X</item_type>
      <item_value>2233</item_value>
    </iary>
    <iary>
      <item_name>illuminance_U_NA</item_name>
      <item_type>X</item_type>
      <item_value>623</item_value>
    </iary>
    <iary>
      <item_name>illuminance_U_PL</item_name>
      <item_type>X</item_type>
      <item_value>2123</item_value>
    </iary>
  </datas>
</EDC>

程式說明

基本ElementTree 操作

import xml.etree.ElementTree as ET

XML = ET.ElementTree()  # 建立 ElementTree 物件
EDC = ET.Element('EDC')  # 建立 Element 物件
XML._setroot(EDC)   # 設定ElementTree XML 的根節點為EDC

_object_id = ET.SubElement(EDC, 'object_id')  # 建立 SubElement 物件 - object_id

# print(ET.dump(XML))  # print Element / ElementTree 內容
XML.write("Output.xml")  # 輸出檔案

output.xml

<EDC><object_id /></EDC>

write() parameter - short_empty_elements

XML.write("Output.xml") → XML.write("Output.xml", short_empty_elements=False)

output.xml

<EDC><object_id></object_id></EDC>

換行與縮排 - pretty_xml

import xml.etree.ElementTree as ET
def pretty_xml(element, indent, newline, level=0):
  if element:  # 判断element是否有子元素
      if (element.text is None) or element.text.isspace():  # 如果element的text没有内容
          element.text = newline + indent * (level + 1)
      else:
          element.text = newline + indent * \
              (level + 1) + element.text.strip() + \
              newline + indent * (level + 1)
          # else:  # 此处两行如果把注释去掉,Element的text也会另起一行
          # element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
  temp = list(element)  # 将element转成list
  for subelement in temp:
      # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
      if temp.index(subelement) < (len(temp) - 1):
          subelement.tail = newline + indent * (level + 1)
      else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
          subelement.tail = newline + indent * level
      pretty_xml(subelement, indent, newline,
                  level=level + 1)  # 对子元素进行递归操作
  return element

XML = ET.ElementTree()  # 建立 ElementTree 物件
EDC = ET.Element('EDC')  # 建立 Element 物件
XML._setroot(EDC)   # 設定ElementTree XML 的根節點為EDC

_object_id = ET.SubElement(EDC, 'object_id')  # 建立 SubElement 物件 - object_id

# 對root Element 進行縮排與換行
EDC = pretty_xml(EDC, "  ", "\n") # 縮排使用兩個空格
# EDC = pretty_xml(EDC, "\t", "\n")  # 縮排使用 tab

XML.write("Output.xml", short_empty_elements=False)  # 輸出檔案

output.xml

<EDC>
  <object_id></object_id>
</EDC>

完整程式碼

import xml.etree.ElementTree as ET
import traceback
import datetime


def item2XML(xml_filename, object_id, product_id, eqp_id, owner, recipe_id, operation, cldate, cltime, datas):
    # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行
    def pretty_xml(element, indent, newline, level=0):
        if element:  # 判断element是否有子元素
            if (element.text is None) or element.text.isspace():  # 如果element的text没有内容
                element.text = newline + indent * (level + 1)
            else:
                element.text = newline + indent * \
                    (level + 1) + element.text.strip() + \
                    newline + indent * (level + 1)
                # else:  # 此处两行如果把注释去掉,Element的text也会另起一行
                # element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level
        temp = list(element)  # 将element转成list
        for subelement in temp:
            # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致
            if temp.index(subelement) < (len(temp) - 1):
                subelement.tail = newline + indent * (level + 1)
            else:  # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个
                subelement.tail = newline + indent * level
            pretty_xml(subelement, indent, newline,
                       level=level + 1)  # 对子元素进行递归操作
        return element
    try:
        XML = ET.ElementTree()  # 建立 ElementTree 物件
        EDC = ET.Element('EDC')  # 建立 Element 物件
        XML._setroot(EDC)   # 設定ElementTree XML 的根節點為EDC

        _object_id = ET.SubElement(EDC, 'object_id')
        _object_id.text = object_id

        _product_id = ET.SubElement(EDC, 'product_id')
        _product_id.text = product_id

        _eqp_id = ET.SubElement(EDC, 'eqp_id')
        _eqp_id.text = eqp_id

        _owner = ET.SubElement(EDC, 'owner')
        _product_id.text = product_id

        _recipe_id = ET.SubElement(EDC, 'recipe_id')
        _recipe_id.text = recipe_id

        _operation = ET.SubElement(EDC, 'operation')
        _operation.text = operation

        _cldate = ET.SubElement(EDC, 'cldate')
        _cldate.text = cldate

        _cltime = ET.SubElement(EDC, 'cltime')
        _cltime.text = cltime

        _datas = ET.SubElement(EDC, 'datas')
        for data in datas:
            _iary = ET.SubElement(_datas, 'iary')

            _item_name = ET.SubElement(_iary, 'item_name')
            _item_name.text = data['item_name']

            _item_type = ET.SubElement(_iary, 'item_type')
            _item_type.text = data['item_type']

            _item_value = ET.SubElement(_iary, 'item_value')
            _item_value.text = str(data['item_value'])
        EDC = pretty_xml(EDC, "  ", "\n")
        XML.write(xml_filename,
                  short_empty_elements=False)  # 寫入檔案
        return True
    except Exception:
        print(traceback.format_exc())
        return False


if __name__ == "__main__":
    object_id = "OBJ_ID"
    product_id = "PROD_ID"
    eqp_id = "EQP_ID"
    owner = "OWNER"
    recipe_id = "RECIPE_ID"
    operation = "OPER"
    cldate = datetime.datetime.now().strftime("%Y-%m-%d")
    cltime = datetime.datetime.now().strftime("%H:%M:%S")
    datas = [
        {"item_name": "illuminance_B_NA", "item_type": "X", "item_value": 751},
        {"item_name": "illuminance_B_PL", "item_type": "X", "item_value": 2233},
        {"item_name": "illuminance_U_NA", "item_type": "X", "item_value": 623},
        {"item_name": "illuminance_U_PL", "item_type": "X", "item_value": 2123},
    ]
    result = item2XML("Output.xml", object_id, product_id, eqp_id,
                      owner, recipe_id, operation, cldate, cltime, datas)
    print(f"IsSuccess: {result}")

參考文獻

  1. Python使用ElementTree处理XML缩进和换行
  2. The ElementTree XML API

#Python #xml







Related Posts

[MTR04] W2 D14 練習四:請寫出一個叫做 star 的 function 並且接受一個參數 n,能回傳 n 個 *。

[MTR04] W2 D14 練習四:請寫出一個叫做 star 的 function 並且接受一個參數 n,能回傳 n 個 *。

C# 自訂義搜尋控件

C# 自訂義搜尋控件

Vue.js 學習旅程Mile 9 – Event Handling 事件處理篇-1:methods & v-on

Vue.js 學習旅程Mile 9 – Event Handling 事件處理篇-1:methods & v-on


Comments